//+---------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 2001.
//
//  File:       N E T C F G A P I . C P P
//
//  Contents:   Functions to illustrate INetCfg API
//
//  Notes:
//
//  Author:     Alok Sinha    15-May-01
//
//----------------------------------------------------------------------------

#include "NetCfgAPI.h"

//
// Function:  HrGetINetCfg
//
// Purpose:   Get a reference to INetCfg.
//
// Arguments:
//    fGetWriteLock  [in]  If TRUE, Write lock.requested.
//    lpszAppName    [in]  Application name requesting the reference.
//    ppnc           [out] Reference to INetCfg.
//    lpszLockedBy   [in]  Optional. Application who holds the write lock.
//
// Returns:   S_OK on success, otherwise an error code.
//
// Notes:
//

HRESULT HrGetINetCfg (IN BOOL fGetWriteLock,
					  IN LPCWSTR lpszAppName,
					  OUT INetCfg** ppnc,
					  LPWSTR *lpszLockedBy)
{
	INetCfg      *pnc = NULL;
	INetCfgLock  *pncLock = NULL;
	HRESULT      hr = S_OK;

	//
	// Initialize the output parameters.
	//

	*ppnc = NULL;

	if ( lpszLockedBy )
	{
		*lpszLockedBy = NULL;
	}
	//
	// Initialize COM
	//

	hr = CoInitialize( NULL );

	if ( hr == S_OK ) {

		//
		// Create the object implementing INetCfg.
		//

		hr = CoCreateInstance( CLSID_CNetCfg,
			NULL, CLSCTX_INPROC_SERVER,
			IID_INetCfg,
			(void**)&pnc );
		if ( hr == S_OK ) {

			if ( fGetWriteLock ) {

				//
				// Get the locking reference
				//

				hr = pnc->QueryInterface( IID_INetCfgLock,
					(LPVOID *)&pncLock );
				if ( hr == S_OK ) {

					//
					// Attempt to lock the INetCfg for read/write
					//

					hr = pncLock->AcquireWriteLock( LOCK_TIME_OUT,
						lpszAppName,
						lpszLockedBy);
					if (hr == S_FALSE ) {
						hr = NETCFG_E_NO_WRITE_LOCK;
					}
				}
			}

			if ( hr == S_OK ) {

				//
				// Initialize the INetCfg object.
				//

				hr = pnc->Initialize( NULL );

				if ( hr == S_OK ) {
					*ppnc = pnc;
					pnc->AddRef();
				}
				else {

					//
					// Initialize failed, if obtained lock, release it
					//

					if ( pncLock ) {
						pncLock->ReleaseWriteLock();
					}
				}
			}

			ReleaseRef( pncLock );
			ReleaseRef( pnc );
		}

		//
		// In case of error, uninitialize COM.
		//

		if ( hr != S_OK ) {
			CoUninitialize();
		}
	}

	return hr;
}

//
// Function:  HrReleaseINetCfg
//
// Purpose:   Get a reference to INetCfg.
//
// Arguments:
//    pnc           [in] Reference to INetCfg to release.
//    fHasWriteLock [in] If TRUE, reference was held with write lock.
//
// Returns:   S_OK on success, otherwise an error code.
//
// Notes:
//

HRESULT HrReleaseINetCfg (IN INetCfg* pnc,
						  IN BOOL fHasWriteLock)
{
	INetCfgLock    *pncLock = NULL;
	HRESULT        hr = S_OK;

	//
	// Uninitialize INetCfg
	//

	hr = pnc->Uninitialize();

	//
	// If write lock is present, unlock it
	//

	if ( hr == S_OK && fHasWriteLock ) {

		//
		// Get the locking reference
		//

		hr = pnc->QueryInterface( IID_INetCfgLock,
			(LPVOID *)&pncLock);
		if ( hr == S_OK ) {
			hr = pncLock->ReleaseWriteLock();
			ReleaseRef( pncLock );
		}
	}

	ReleaseRef( pnc );

	//
	// Uninitialize COM.
	//

	CoUninitialize();

	return hr;
}

//
// Function:  HrGetComponentEnum
//
// Purpose:   Get network component enumerator reference.
//
// Arguments:
//    pnc         [in]  Reference to INetCfg.
//    pguidClass  [in]  Class GUID of the network component.
//    ppencc      [out] Enumerator reference.
//
// Returns:   S_OK on success, otherwise an error code.
//
// Notes:
//

HRESULT HrGetComponentEnum (INetCfg* pnc,
							IN const GUID* pguidClass,
							OUT IEnumNetCfgComponent **ppencc)
{
	INetCfgClass  *pncclass;
	HRESULT       hr;

	*ppencc = NULL;

	//
	// Get the class reference.
	//

	hr = pnc->QueryNetCfgClass( pguidClass,
		IID_INetCfgClass,
		(PVOID *)&pncclass );

	if ( hr == S_OK ) {

		//
		// Get the enumerator reference.
		//

		hr = pncclass->EnumComponents( ppencc );

		//
		// We don't need the class reference any more.
		//

		ReleaseRef( pncclass );
	}

	return hr;
}

//
// Function:  HrGetFirstComponent
//
// Purpose:   Enumerates the first network component.
//
// Arguments:
//    pencc      [in]  Component enumerator reference.
//    ppncc      [out] Network component reference.
//
// Returns:   S_OK on success, otherwise an error code.
//
// Notes:
//

HRESULT HrGetFirstComponent (IN IEnumNetCfgComponent* pencc,
							 OUT INetCfgComponent **ppncc)
{
	HRESULT  hr;
	ULONG    ulCount;

	*ppncc = NULL;

	pencc->Reset();

	hr = pencc->Next( 1,
		ppncc,
		&ulCount );
	return hr;
}

//
// Function:  HrGetNextComponent
//
// Purpose:   Enumerate the next network component.
//
// Arguments:
//    pencc      [in]  Component enumerator reference.
//    ppncc      [out] Network component reference.
//
// Returns:   S_OK on success, otherwise an error code.
//
// Notes:     The function behaves just like HrGetFirstComponent if
//            it is called right after HrGetComponentEnum.
//
//

HRESULT HrGetNextComponent (IN IEnumNetCfgComponent* pencc,
							OUT INetCfgComponent **ppncc)
{
	HRESULT  hr;
	ULONG    ulCount;

	*ppncc = NULL;

	hr = pencc->Next( 1,
		ppncc,
		&ulCount );
	return hr;
}

//
// Function:  ReleaseRef
//
// Purpose:   Release reference.
//
// Arguments:
//    punk     [in]  IUnknown reference to release.
//
// Returns:   Reference count.
//
// Notes:
//

VOID ReleaseRef (IN IUnknown* punk)
{
	if ( punk ) {
		punk->Release();
	}

	return;
}